#include "bll.h"
#include "../Icon/server.xpm"
#include "../Icon/db.xpm"
#include "../Icon/table.xpm"
#include "../Icon/sp.xpm"
#include "../Icon/view.xpm"
#include "../Icon/folder.xpm"
#include "../Icon/parm.xpm"
#include "../Icon/func.xpm"
#include "wx/strconv.h"
#include "wx/tokenzr.h"
#include "wx/xml/xml.h"
#include "wx/file.h"
#include "wx/laywin.h"
#include "wx/imaglist.h"
//#include "../Control/ResultTable.h"
//#include "../Control/UIThread.h"
//#include "../conndlg.h"

#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(ConfArray); 
WX_DEFINE_OBJARRAY(ResultArray); 

wxMBConv* charset = new wxCSConv(wxFONTENCODING_SYSTEM);

void BLL::AddDbListToTreeCtrl(MyUI* ui,bool initial,int pos){
	wxImageList *images = new wxImageList(16, 16, true);
    wxBitmap bitmap[11];
    bitmap[0] = wxBitmap(server_xpm);
    bitmap[1] = wxBitmap(db_xpm);
    bitmap[2] = wxBitmap(table_xpm);
	bitmap[3] = wxBitmap(folder_xpm);
    bitmap[4] = wxBitmap(sp_xpm);
    bitmap[5] = wxBitmap(parm_xpm);
	bitmap[6] = bitmap[3];//wxBitmap(folder_xpm);
	bitmap[7] = wxBitmap(func_xpm);
	bitmap[8] = bitmap[5];
	bitmap[9] = bitmap[3];
	bitmap[10] = wxBitmap(view_xpm);
    for(unsigned int i=0;i<WXSIZEOF(bitmap);i++)
        images->Add(bitmap[i]);
	wxTreeCtrl* treectrl = ui->treeview;
    treectrl->AssignImageList(images);
    wxTreeItemId root;
	if ( treectrl->GetRootItem().IsOk())
		root = treectrl->GetRootItem();
	else
		root = treectrl->AddRoot(ui->serverInfo->conn_name,0);

	wxString title;
	title.Append(ui->serverInfo->conn_name);
	title.Append(wxT(" (MySQL "));
	title.Append(wxString(ui->serverInfo->mysql->server_version,*charset));
	title.Append(wxT(")"));
	wxTreeItemId root1;
	
	if ( initial )
		root1 = treectrl->AppendItem(root,title,0);
	else{
		wxTreeItemIdValue cookie;
		root1 = treectrl->GetFirstChild(root,cookie);
		for ( int i=0 ; i < pos; ++i)
			root1 = treectrl->GetNextSibling(root1);
	}
		

	QueryResultList* res = DoQuery(ui->serverInfo->mysql,"show databases");
	wxChoice* currentDbChoice = ui->currentDb;
	currentDbChoice->Clear();
	wxString dbList;
	if(res->head->type == sets){
		for(int j=1; j<=res->head->row; ++j){
			wxString item = wxString(res->head->result[j],*charset);
			wxTreeItemId t = treectrl->AppendItem(root1,item,db,-1,new wxTreeItemData());
			dbList.Append(item);
			if ( j != res->head->row ) 
				dbList.Append(TAB);
			currentDbChoice->Append(item);
		}
	}
	treectrl->Expand(root1);
	currentDbChoice->Select(currentDbChoice->FindString(wxString(ui->serverInfo->mysql->db,*charset)));
	FreeQueryResultList(res);
	EditNotebook* editNotebook = ui->editNotebook;
	if ( initial )
		editNotebook->AddDbList(dbList);
	else
		editNotebook->AddDbList(dbList,false,pos);
}

wxTreeItemId BLL::GetParentItemIdByLayer(wxTreeItemId cur,wxTreeCtrl* treeCtrl,int layer){
	wxTreeItemId parent = cur;
	for( int i = 0; i < layer; i++){
		parent = treeCtrl->GetItemParent(parent);
	}
	return parent;
}

void BLL::OnTreeCtrlActived(MyUI* ui,wxTreeItemId cur){
	wxTreeCtrl* treeCtrl = ui->treeview;
	wxStatusBar* s_bar = ui->s_bar;
	wxChoice* currentDbChoice = ui->currentDb;
	EditNotebook* editNotebook = ui->editNotebook;
    int id = treeCtrl->GetItemImage(cur);
    MYSQL* mysql = NULL;
	// Db node, find table list
	if ( id == db ) {
		if ( treeCtrl->ItemHasChildren(cur) )
			return;
		//wxTreeItemId parent = treeCtrl->GetItemParent(cur);
		wxTreeItemId parent = GetParentItemIdByLayer(cur,treeCtrl,1);
		mysql = GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		wxString db = treeCtrl->GetItemText(cur);
        AddTableListToTreeCtrl(mysql,db,cur,treeCtrl,s_bar,currentDbChoice);
    }
	// Table node, show table structure
	else if ( id == table ) {
        wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("desc ") + db + wxT(".") + treeCtrl->GetItemText(cur);
		wxTreeItemId parent = GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        //DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log);
		DoSQLQuery(ui,query);
    }
	// add sp
/*	else if ( id == sp_folder ) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select ROUTINE_NAME from information_schema.ROUTINES where routine_schema = '");
		query.Append(db);
		query.Append(wxT("' and ROUTINE_TYPE='PROCEDURE'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,sp);
	}
	// show create sp
	else if ( id == sp_parm ) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString sp = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,4);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateRoutine(mysql,db,sp,result,r_sp);
	}
	// get sp parms or show create sp
	else if ( id == sp || id == func) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur)));
		RoutineType rType = id == sp ? r_sp : r_func;
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,3);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AddRoutineParmsToTreeCtrl(mysql,db,treeCtrl->GetItemText(cur),cur,treeCtrl,result,(TreeNodeType)id,rType);
	}
	else if ( id == func_folder){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select ROUTINE_NAME from information_schema.ROUTINES where routine_schema = '");
		query.Append(db);
		query.Append(wxT("' and ROUTINE_TYPE='FUNCTION'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,func);
	}
	else if ( id == func_parm){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString sp = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,4);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateRoutine(mysql,db,sp,result,r_func);
	}
	else if ( id == view_folder){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select table_name from information_schema.tables where table_type<>'SYSTEM VIEW' and table_type<>'BASE TABLE' and table_schema='");
		query.Append(db);
		query.Append(wxT("'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,view);
	}
	else if ( id == view){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString view = treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,3);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateView(mysql,db,view,result);
	}*/
}

MYSQL* BLL::GetMySQLByTreeCtrlLayer(wxTreeItemId root,wxTreeCtrl* treeCtrl,EditNotebook* editNotebook){
	int index = GetTreeCtrlLayer(root,treeCtrl);
	return editNotebook->GetMySQLByIndex(index);
}

int BLL::GetTreeCtrlLayer(wxTreeItemId root,wxTreeCtrl* treeCtrl){
	int index = 0;
	wxTreeItemId prev =  treeCtrl->GetPrevSibling(root);
	while ( prev.IsOk() ){
		++index;
		prev = treeCtrl->GetPrevSibling(prev);
	}
	return index;
}

void BLL::DoSQLQuery(MyUI* ui, int type)
{
	if ( type == ID_TB_RUN_LINE || type == ID_MENUITEM_BUILD_RUN_LINE )
		DoSQLQuery(ui,ui->editNotebook->GetCurrentLineText());
	else if (type == ID_TB_RUN_TEXT)
		return;
	else if ( type == ID_TB_RUN || type == ID_MENUITEM_BUILD_RUN_ALL ){
		wxString query = ui->editNotebook->GetCurrentSelectedText();
		query = (query == wxEmptyString) ? ui->editNotebook->GetCurrentText() : query;
		DoSQLQuery(ui,query);
	}
	else{
		
	}
}

void BLL::DoSQLQuery(MyUI* ui,const wxString& query,int type){
//MYSQL* mysql,wxString query,ResultNotebook* result,wxStatusBar* s_bar,wxChoice* currentDbChoice,Edit* log,int type,wxMutex* mutex){

	ui->editNotebook->GetCurrentEdit()->SetFocus();

	MYSQL* mysql = ui->serverInfo->mysql;
	ResultNotebook* result = ui->result;
	wxStatusBar* s_bar = ui->s_bar;
	wxChoice* currentDbChoice = ui->currentDb;
	Edit* log = ui->log;

	QueryResultList* resultList = (QueryResultList*)malloc(sizeof(QueryResultList));
	resultList->head = NULL;
	resultList->length = 0;

	QueryResult* cur = NULL;
	QueryResult* rr = NULL;

	ResultArray array;

	UIThread* thread = ui->sqlThread;
	thread = new UIThread(resultList,mysql,ui->editNotebook,query,cur,rr,result,s_bar,currentDbChoice,log,type,array,BLL::FetchingData);
	if (thread->Create(100) != wxTHREAD_NO_ERROR ){
		wxMessageBox(_("CREATE THREAD ERROR"));
		return;
	}
	thread->Run();

}

void BLL::AddTableListToTreeCtrl(MYSQL*mysql,wxString db,wxTreeItemId cur,wxTreeCtrl* treeCtrl,wxStatusBar* s_bar,wxChoice* currentDbChoice){
	// Change DB
	QueryResultList* r = DoQuery(mysql, (wxT("use ")+ db).mb_str(*charset));
	if (!CheckQueryResultList(r)){
		return;
	}
	FreeQueryResultList(r);

	wxString query;
	// Add sp node, for mysql version higer than 4.0
	if(GetMySQLVersion(mysql) > 4){
		treeCtrl->DeleteChildren(cur);
		treeCtrl->AppendItem(cur,wxT("Stored Procedure"),sp_folder);
		treeCtrl->AppendItem(cur,wxT("Function"),func_folder);
		treeCtrl->AppendItem(cur,wxT("View"),view_folder);
		// Add table list to TreeCtrl
		query = wxT("select table_name from information_schema.TABLES where table_type<>'VIEW' and table_schema='");
		query.Append(db);
		query.Append(wxT("'"));
	}
	else{
		query = wxT("show tables");
	}

	QueryResultList* res = DoQuery(mysql, query.mb_str(*charset));

	for(int j = 1; j <= res->head->row; ++j){
		char* s = res->head->result[j];
		wxString item = wxString(s,*charset);
		treeCtrl->AppendItem(cur,item,table,-1,new wxTreeItemData());
	}

	FreeQueryResultList(res);

	SetCurrentDb(mysql,s_bar,currentDbChoice);
}

float BLL::GetMySQLVersion(MYSQL* mysql){
	return atof(mysql->server_version); 
}

void _ReadConfList(wxChoice* lsSaved,ConfArray* array){
	if ( !wxFile::Exists(CONF) )
		return;
    wxXmlDocument doc;
    doc.Load(CONF);
    wxXmlNode* child = doc.GetRoot()->GetChildren();
    while(child){
        wxString name = child->GetPropVal(wxT("name"),wxEmptyString);
        wxString ip = child->GetPropVal(wxT("ip"),wxEmptyString);
        wxString user =  child->GetPropVal(wxT("user"),wxEmptyString);
        wxString pwd = child->GetPropVal(wxT("pwd"),pwd);
        wxString port = child->GetPropVal(wxT("port"),port);
        wxString db =  child->GetPropVal(wxT("db"),db);
        ConfInfo* info = new ConfInfo(name,ip,user,pwd,port,db);
        array->Add(info);
        lsSaved->Append(name);
        child = child->GetNext();
    }
}

bool BLL::CheckQueryResultList(QueryResultList* res){
	unsigned error_no = res->head->error_no;
	if ( error_no == 2006 ){
		wxMessageBox(MYSQL_GONE_AWAY,MSG_ERR);
		FreeQueryResultList(res);
		return false;
	}
	else if ( error_no == 1142 ){
		wxMessageBox(MYSQL_PRIV_WARNING,MSG_ERR);
		FreeQueryResultList(res);
		return false;
	}
	else if ( error_no > 0 ){
		wxString msg;
		msg.Printf(MYSQL_ERROR,error_no);
		wxMessageBox(msg,MSG_ERR);
		FreeQueryResultList(res);
		return false;
	}
	return true;
}

void BLL::SetCurrentDb(MYSQL* mysql,wxStatusBar* s_bar,wxChoice* currentDbChoice){
	QueryResultList* res = DoQuery(mysql,"select database()");
	if ( res->head->error_no == 2006 ){
		wxMessageBox(MYSQL_GONE_AWAY,MSG_ERR) ;
	}
	else{
		wxString db = wxString(res->head->result[1],*charset);
		s_bar->SetStatusText(db,3);
		currentDbChoice->Select(currentDbChoice->FindString(db));
	}
	FreeQueryResultList(res);
}

float BLL::FetchingData(ResultArray& array,MYSQL* mysql,wxString& query,wxStatusBar* s_bar,QueryResultList* resultList,QueryResult* cur,QueryResult* r){
    //s_bar->SetStatusText(wxT("Fecting Data"),0);
	wxDateTime start = wxDateTime::UNow();
	DoQuery(mysql,query.mb_str(*charset),resultList,cur,r);
	QueryResult* head = resultList->head;

	int sets_count = 0;
	unsigned int error_no = 0;
	while(head){
		QResult* t =  new QResult();
		if ( head->type == sets ){
			char** table = head->result;
			t->row = head->row;
			t->col = head->col;
			for( int j = 0; j < (head->row+1)*head->col ; ++j){
				if (table[j] != NULL)
					(t->result).Add(wxString(table[j],*charset));
				else{
					t->nullArray.Add(j);
					(t->result).Add(wxT("NULL"));
				}
			}
			wxString f = wxT("\n%d rows in set\n");
			t->msg = wxString::Format(f,head->affected_rows);
			f.Clear();
			++sets_count;
		}
		else if ( head->type == error ){
			t->type = error;
			t->msg = wxString::Format(wxT("\nError %d: "),head->error_no);
			t->msg.Append(wxString(head->msg,*charset));
			t->msg.Append(wxT("\n"));
			error_no = head->error_no;
		}
		else if ( head->type == affectedrows){
			t->type = affectedrows;
			if ( head->msg){
				t->msg = wxString(ENTER);
				t->msg.Append(wxString(head->msg,*charset));		
			}
			else
				t->msg = wxString::Format(wxT("\nQuery OK, %d rows affected\n"),head->affected_rows);
		}
		array.Add(t);
		head = head->next;
	}
	FreeQueryResultList(resultList);
	wxDateTime end = wxDateTime::UNow();
    wxTimeSpan span = end - start ;
    float sec = (1.0*span.GetMilliseconds().ToLong()) / 1000;
	return sec;
    //wxString sb;
    //sb.Printf(wxT("Fetching Data: %.5f sec"),sec);
    //s_bar->SetStatusText(sb,4);
}

#include <string.h>
void BLL::LoadingData(ResultArray& array,int sets_count,MYSQL* mysql,wxString& query,EditNotebook* editNotebook,ResultNotebook* result,wxStatusBar* s_bar,wxChoice* currentDbChoice,Edit* log,int type){
	
	editNotebook->GetCurrentEdit()->SetFocus();

    s_bar->SetStatusText(wxT("Loading Data"),0);
	
	wxDateTime start = wxDateTime::UNow();
	unsigned int error_no = 0;
	
	if ( type == 0){
		result->BindResult(array,sets_count);
	}
	else{
		//_BindResultInText(result,array,sets_count);
	}
	array.Clear();
	
	QueryResult* r = GetExecuteQueryInfo(mysql,NULL);
	if ( r ->type == error ){
		wxString err = wxString::Format(wxT("\nError %d: "),r->error_no);
		err.Append(wxString(r->msg,*charset));
		wxTextCtrl* msgText = result->GetTextCtrl();
		msgText->SetDefaultStyle(wxColor(wxT("Red")));
		msgText->AppendText(err);
		result->SetSelection(1);
	}
	FreeQueryResult(r);
	
	// Query Log
	wxStringTokenizer tkz(query,ENTER);
	while(tkz.HasMoreTokens()){
		wxString sql = tkz.GetNextToken();
		if ( sql == 13 )
			continue;
		log->AppendText(sql);
		log->AppendText(ENTER);
		log->LineScrollDown();
	}
	wxDateTime end = wxDateTime::UNow();
    wxTimeSpan span = end - start ;
    float sec = (1.0*span.GetMilliseconds().ToLong()) / 1000;
    wxString sb;
    sb.Printf(wxT("Loading Data: %.5f sec"),sec);
    s_bar->SetStatusText(sb,5);
	
	s_bar->SetStatusText(wxString(mysql->host,*charset),1);
	s_bar->SetStatusText(wxString(mysql->user,*charset),2);
	// Set Current Db
	if ( error_no !=0 )
		return;
	SetCurrentDb(mysql,s_bar,currentDbChoice);

	float totalCostTime = sec + atof(s_bar->GetStatusText(4).Mid(15,8).ToAscii());
	sb.Printf(wxT("Total Cost Time: %.5f sec"),totalCostTime);
	s_bar->SetStatusText(sb,6);
	s_bar->SetStatusText(wxT("Finish"),0);
	editNotebook->GetCurrentEdit()->SetFocus();

}

MYSQL* _ConnectToMySQL(MYSQL* mysql,const wxString& host,wxString user,wxString passwd,wxString db,wxString port){
	return ConnectToMySQL(mysql,host.mb_str(),user.mb_str(),passwd.mb_str(),db.mb_str(),atoi(port.mb_str()));
}

wxString _GetMySQLError(MYSQL* mysql){
	return wxString((GetExecuteQueryInfo(mysql,NULL))->msg,*charset);
}

void _SaveConf(wxString name,wxString ip,wxString user,wxString pwd,wxString port,wxString db){
	if ( !wxFile::Exists(CONF) ){
		wxFile file;
		file.Create(CONF);
		file.Write(wxT("<xml></xml>"),wxConvUTF8);
		file.Close();
	}
    wxXmlDocument doc;
    doc.Load(CONF);
    wxXmlNode* root = doc.GetRoot();
    wxXmlNode* child = new wxXmlNode(root,wxXML_ELEMENT_NODE,wxT("Conf"),wxEmptyString,NULL,root->GetChildren());
    child->AddProperty(wxT("name"),name == wxEmptyString ? ip : name);
    child->AddProperty(wxT("ip"),ip);
    child->AddProperty(wxT("user"),user);
    child->AddProperty(wxT("pwd"),pwd);
    child->AddProperty(wxT("port"),port);
    child->AddProperty(wxT("db"),db);
    doc.Save(CONF);
}
MYSQL* _InitMySQL(MYSQL* mysql){
	return InitMySQL(mysql);
}

/*void _AddDbListToTreeCtrl(MYSQL* mysql,wxTreeCtrl* treectrl,EditNotebook* editNotebook,wxString connInfo,wxChoice* currentDbChoice,bool initial,int pos){
	wxImageList *images = new wxImageList(16, 16, true);
    wxBitmap bitmap[11];
    bitmap[0] = wxBitmap(server_xpm);
    bitmap[1] = wxBitmap(db_xpm);
    bitmap[2] = wxBitmap(table_xpm);
	bitmap[3] = wxBitmap(folder_xpm);
    bitmap[4] = wxBitmap(sp_xpm);
    bitmap[5] = wxBitmap(parm_xpm);
	bitmap[6] = bitmap[3];//wxBitmap(folder_xpm);
	bitmap[7] = wxBitmap(func_xpm);
	bitmap[8] = bitmap[5];
	bitmap[9] = bitmap[3];
	bitmap[10] = wxBitmap(view_xpm);
    for(unsigned int i=0;i<WXSIZEOF(bitmap);i++)
        images->Add(bitmap[i]);
    treectrl->AssignImageList(images);
    wxTreeItemId root;
	if ( treectrl->GetRootItem().IsOk())
		root = treectrl->GetRootItem();
	else
		root = treectrl->AddRoot(connInfo,0);

	wxString title;
	title.Append(connInfo);
	title.Append(wxT(" (MySQL "));
	title.Append(wxString(mysql->server_version,*charset));
	title.Append(wxT(")"));
	wxTreeItemId root1;
	
	if ( initial )
		root1 = treectrl->AppendItem(root,title,0);
	else{
		wxTreeItemIdValue cookie;
		root1 = treectrl->GetFirstChild(root,cookie);
		for ( int i=0 ; i < pos; ++i)
			root1 = treectrl->GetNextSibling(root1);
	}
		

	QueryResultList* res = DoQuery(mysql,"show databases");
	currentDbChoice->Clear();
	wxString dbList;
	if(res->head->type == sets){
		for(int j=1; j<=res->head->row; ++j){
			wxString item = wxString(res->head->result[j],*charset);
			wxTreeItemId t = treectrl->AppendItem(root1,item,db,-1,new wxTreeItemData());
			dbList.Append(item);
			if ( j != res->head->row ) 
				dbList.Append(TAB);
			currentDbChoice->Append(item);
		}
	}
	treectrl->Expand(root1);
	currentDbChoice->Select(currentDbChoice->FindString(wxString(mysql->db,*charset)));
	FreeQueryResultList(res);
	if ( initial )
		editNotebook->AddDbList(dbList);
	else
		editNotebook->AddDbList(dbList,false,pos);
}

void _BindResultInText(ResultNotebook* result,ResultArray& resultArray,int sets_count){
	result->ClearMessageText();
	result->GetText()->ClearAll();
	for(unsigned int i = 0;i < resultArray.GetCount();++i){

		QResult& res = resultArray[i];
		if ( sets_count == 0)
			result->SetSelection(1);
		if ( res.type == sets ){
			int col = res.col;
			int row = res.row;
			for( int r = 1; r <= row;++r){
				wxString row_info;
				result->GetText()->AppendText(row_info.Format(wxT("***************************** %d. row *****************************\n"),r));
				for( int c = 0; c < col; ++c ){
					result->GetText()->AppendText(res.result[c]);
					result->GetText()->AppendText(wxT(": "));
					result->GetText()->AppendText(res.result[r*col+c]);
					result->GetText()->AppendText(ENTER);
				}
			}
			result->SetSelection(2);
		}
		if ( res.type == error ){
			result->GetMessgae()->SetDefaultStyle(wxTextAttr(*wxRED));
			result->SetSelection(1);
		}
		result->GetMessgae()->AppendText(res.msg);
	}
}


wxTreeItemId _GetParentItemIdByLayer(wxTreeItemId cur,wxTreeCtrl* treeCtrl,int layer){
	wxTreeItemId parent = cur;
	for( int i = 0; i < layer; i++){
		parent = treeCtrl->GetItemParent(parent);
	}
	return parent;
}

void _OnTreeCtrlReloadActived(int id,EditNotebook* editNotebook,wxTreeItemId cur,wxTreeCtrl* treeCtrl,wxStatusBar* s_bar,wxChoice* currentDbChoice,Edit* log,ResultNotebook* result){
	if ( id == DB_DEL){
		wxMessageBox(_("aa"));
	}
	else if( id == DB_REFRESH ){
		treeCtrl->DeleteChildren(cur);
		treeCtrl->SetItemHasChildren(false);
		_OnTreeCtrlActived(editNotebook,cur,treeCtrl,s_bar,currentDbChoice,log,result);
	}
	else if( id == TABLE_PREVIEW){
        wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("SELECT * FROM ") + db + wxT(".") + treeCtrl->GetItemText(cur) + wxT(" limit 30");
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log);
	}
	else if ( id == TABLE_SHOW_DESC){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("desc ") + db + wxT(".") + treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log);
	}
	else if ( id == TABLE_SHOW_INDEX){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("SHOW INDEX FROM ") + db + wxT(".") + treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log);
	}
	else if ( id == TABLE_SHOW_CREATE){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("SHOW CREATE TABLE ") + db + wxT(".") + treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log,1);
	}
	else if ( id == TABLE_PROPERTY){
		char a = '\'';
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("SHOW TABLE STATUS LIKE ") + wxString::FromAscii(a) + treeCtrl->GetItemText(cur) + wxString::FromAscii(a);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log,1);
	}
	else if ( id == SERVER_RECONNECT ){
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(cur,treeCtrl,editNotebook);
		mysql = ConnectToMySQL(mysql,mysql->host,mysql->user,mysql->passwd,mysql->db,mysql->port);
		wxString msg = wxT("# Reconnect to Server ");
		msg.Append(wxString(mysql->host,*charset));
		log->AppendText(msg);
	}
	else if ( id == SERVER_REFRESH ){
		treeCtrl->DeleteChildren(cur);
		treeCtrl->SetItemHasChildren(false);
		int index = _GetTreeCtrlLayer(cur,treeCtrl);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(cur,treeCtrl,editNotebook);
		_AddDbListToTreeCtrl(mysql,treeCtrl,editNotebook,editNotebook->GetCurrentText(),currentDbChoice,false,index);
	}
	else if ( id == SERVER_CLOSE ){
		int index = _GetTreeCtrlLayer(cur,treeCtrl);
		MYSQL* mysql = _GetMySQLByTreeCtrlLayer(cur,treeCtrl,editNotebook);
		_CloseMySQL(mysql);
		editNotebook->ClosePageByIndex(index);
		treeCtrl->Delete(cur);
	}
}
void _OnTreeCtrlActived(EditNotebook* editNotebook,wxTreeItemId cur,wxTreeCtrl* treeCtrl,wxStatusBar* s_bar,wxChoice* currentDbChoice,Edit* log,ResultNotebook* result){
    int id = treeCtrl->GetItemImage(cur);
    MYSQL* mysql = NULL;
	// Db node, find table list
	if ( id == db ) {
		if ( treeCtrl->ItemHasChildren(cur) )
			return;
		//wxTreeItemId parent = treeCtrl->GetItemParent(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,1);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		wxString db = treeCtrl->GetItemText(cur);
        _AddTableListToTreeCtrl(mysql,db,cur,treeCtrl,s_bar,currentDbChoice);
    }
	// Table node, show table structure
	else if ( id == table ) {
        wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
        wxString query = wxT("desc ") + db + wxT(".") + treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
        _DoSQLQuery(mysql,query,result,s_bar,currentDbChoice,log);
    }
	// add sp
	else if ( id == sp_folder ) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select ROUTINE_NAME from information_schema.ROUTINES where routine_schema = '");
		query.Append(db);
		query.Append(wxT("' and ROUTINE_TYPE='PROCEDURE'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,sp);
	}
	// show create sp
	else if ( id == sp_parm ) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString sp = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,4);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateRoutine(mysql,db,sp,result,r_sp);
	}
	// get sp parms or show create sp
	else if ( id == sp || id == func) {
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur)));
		RoutineType rType = id == sp ? r_sp : r_func;
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,3);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AddRoutineParmsToTreeCtrl(mysql,db,treeCtrl->GetItemText(cur),cur,treeCtrl,result,(TreeNodeType)id,rType);
	}
	else if ( id == func_folder){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select ROUTINE_NAME from information_schema.ROUTINES where routine_schema = '");
		query.Append(db);
		query.Append(wxT("' and ROUTINE_TYPE='FUNCTION'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,func);
	}
	else if ( id == func_parm){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString sp = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,4);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateRoutine(mysql,db,sp,result,r_func);
	}
	else if ( id == view_folder){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(cur));
		wxString query = wxT("select table_name from information_schema.tables where table_type<>'SYSTEM VIEW' and table_type<>'BASE TABLE' and table_schema='");
		query.Append(db);
		query.Append(wxT("'"));
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,2);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_AttachListToTreeCtrl(mysql,db,query.mb_str(*charset),cur,treeCtrl,view);
	}
	else if ( id == view){
		wxString db = treeCtrl->GetItemText(treeCtrl->GetItemParent(treeCtrl->GetItemParent(treeCtrl->GetItemParent(cur))));
		wxString view = treeCtrl->GetItemText(cur);
		wxTreeItemId parent = _GetParentItemIdByLayer(cur,treeCtrl,3);
		mysql = _GetMySQLByTreeCtrlLayer(parent,treeCtrl,editNotebook);
		_ShowCreateView(mysql,db,view,result);
	}
}

void _AttachListToTreeCtrl(MYSQL* mysql,wxString db,const char* query,wxTreeItemId cur,wxTreeCtrl* treeCtrl,TreeNodeType nodeType){
	// Change DB
	FreeQueryResultList(DoQuery(mysql, (wxT("use ")+ db).mb_str(*charset)));

	// clear sub tree
	treeCtrl->DeleteChildren(cur);

	// attach list to treectrl
	QueryResultList* res = DoQuery(mysql, query);
	if (!_CheckQueryResultList(res))
		return;
	for(int j = 1; j <= res->head->row; ++j){
		wxString item = wxString(res->head->result[j],*charset);
		treeCtrl->AppendItem(cur,item,nodeType,-1,new wxTreeItemData());
	}
	FreeQueryResultList(res);

}

void _ShowCreateRoutine(MYSQL* mysql,wxString db,wxString sp,ResultNotebook* result,RoutineType type){
	// Change DB
	FreeQueryResultList(DoQuery(mysql, (wxT("use ")+ db).mb_str(*charset)));

	// show sp
	wxString query = wxEmptyString;
	if ( type == r_sp )
		query = wxT("show create procedure ") + sp;
	else if ( type == r_func ) 
		query = wxT("show create function ") + sp;

	QueryResultList* res = DoQuery(mysql, query.mb_str(*charset));
	if (!_CheckQueryResultList(res))
		return;
	if( _GetMySQLVersion(mysql) >= 5.1 )
		result->GetSQLEditor()->SetText(wxString(res->head->result[8],*charset));
	else if (_GetMySQLVersion(mysql) >= 5.0)
		result->GetSQLEditor()->SetText(wxString(res->head->result[5],*charset));
	result->GetSQLEditor()->AppendText(wxT(" "));
	result->SetSelection(2);

	FreeQueryResultList(res);
}

void _AddRoutineParmsToTreeCtrl(MYSQL* mysql,wxString db,wxString sp,wxTreeItemId cur,wxTreeCtrl* treeCtrl,ResultNotebook* result,TreeNodeType type,RoutineType rType){
	// Change DB
	FreeQueryResultList(DoQuery(mysql, (wxT("use ")+ db).mb_str(*charset)));
	
	// get sp parms
	treeCtrl->DeleteChildren(cur);
	wxString query = wxT("select param_list from mysql.proc where db='");
	query.Append(db);
	query.Append(wxT("' and name='"));
	query.Append(sp);
	query.Append(wxT("'"));

	QueryResultList* res = DoQuery(mysql, query.mb_str(*charset));
	if (!_CheckQueryResultList(res))
		return;
	wxString item = wxString(res->head->result[1],*charset);
	if ( item == wxEmptyString){
		_ShowCreateRoutine(mysql,db,sp,result,rType);
	}
	else{
		wxStringTokenizer tkz(item, wxT(","));
		while ( tkz.HasMoreTokens() ){
			wxString token = tkz.GetNextToken();
			treeCtrl->AppendItem(cur,token.Trim(false),type+1,-1,new wxTreeItemData());
		}
	}

}

void _ShowCreateView(MYSQL* mysql,wxString db,wxString view,ResultNotebook* result){
	
	FreeQueryResultList(DoQuery(mysql, (wxT("use ")+ db).mb_str(*charset)));

	wxString query = wxT("show create view ");
	query.Append(view);
	QueryResultList* res = DoQuery(mysql, query.mb_str(*charset));

	if (!_CheckQueryResultList(res))
		return;

	if ( _GetMySQLVersion(mysql) >= 5.1 )
		result->GetSQLEditor()->SetText(wxString(res->head->result[5],*charset));
	else if (_GetMySQLVersion(mysql) >= 5.0 )
		result->GetSQLEditor()->SetText(wxString(res->head->result[3],*charset));
	result->GetSQLEditor()->AppendText(wxT(" "));
	result->SetSelection(2);
	

	FreeQueryResultList(res);

}





void _ChangeMySQLServer(MYSQL* mysql,wxTreeCtrl* treectrl,wxString connInfo,wxChoice* currentDbChoice,Edit* log){
	treectrl->DeleteAllItems();
	currentDbChoice->Clear();
//	_AddDbListToTreeCtrl(mysql,treectrl,connInfo+wxT(" (MySQL ")+wxString(mysql->server_version,*charset)+wxT(")"),currentDbChoice);
	log->AppendText(wxT("# Change Server to ") + wxString(mysql->host,*charset) + ENTER);
}

void _CloseMySQL(MYSQL* mysql){
	CloseMySQL(mysql);
}

void _ExportResult(ResultNotebook* result,wxString filename){
	ResultArray array = result->GetResults();
	if ( array.GetCount() != 1 )
		return;
	QResult res = array[0];
	int row = res.row + 1;
	int col = res.col;
	wxFile file(filename,wxFile::write_append);
	for(int i=col; i< row*col; i++){
		file.Write(res.result[i]);
		if ( (i+1) % col == 0 )
			file.Write(ENTER);
		else
			file.Write(TAB);
	}
	file.Close();
}

void _OnPageChanged(int old_index,int new_index,EditNotebook* editNotebook,wxChoice* currentDbChoice,wxStatusBar* s_bar){
	if ( editNotebook->GetDbLists().GetCount() == 0 )
		return;
	editNotebook->SetSelectedByIndex(old_index,currentDbChoice->GetSelection());
	wxString dbList = editNotebook->GetDbListByIndex(new_index);
	if ( dbList == wxEmptyString )
		return;
	wxStringTokenizer tkz(dbList, TAB);
	currentDbChoice->Clear();
	while ( tkz.HasMoreTokens() ){
		wxString token = tkz.GetNextToken();
		currentDbChoice->Append(token);
	}
	//currentDbChoice->Select(currentDbChoice->FindString(wxString(editNotebook->GetMySQLByIndex(index)->db,*charset)));
	currentDbChoice->SetSelection(editNotebook->GetSelectedByIndex(new_index));
	s_bar->SetStatusText(currentDbChoice->GetStringSelection(),3);
}

void _AddNewConnection(wxTreeCtrl* treectrl,EditNotebook* editNotebook,wxChoice* currentDbChoice,wxStatusBar* s_bar){
	ServerInfo* serverInfo = new ServerInfo();
	ConnDlg connDlg(serverInfo,wxID_ANY,wxT("iMySQL-Front"),wxDefaultPosition);
	int res = connDlg.ShowModal();
	if ( res == wxID_CANCEL){
		_CloseMySQL(serverInfo->mysql);
		delete serverInfo;
		return ;
	}
	editNotebook->AddEdit(serverInfo->mysql,serverInfo->conn_name);
	editNotebook->GetEditByIndex(editNotebook->GetEditArray().GetCount()-1)->SetFocus();
	MYSQL* mysql = editNotebook->GetCurrentMySQL();
	_AddDbListToTreeCtrl(mysql,treectrl,editNotebook,serverInfo->conn_name,currentDbChoice);
	_SetStatusBar(mysql,s_bar);
}

void _SetStatusBar(MYSQL* mysql,wxStatusBar* s_bar){
	s_bar->SetStatusText(wxString(mysql->host,*charset),1);
	s_bar->SetStatusText(wxString(mysql->user,*charset),2);
	s_bar->SetStatusText(wxString(mysql->db,*charset),3);
}*/